
#pragma once

#include <flash/flash.h>
#include <flash/nand_cmd.h>

#define SOFT_ECC_DATA_LEN  256
#define SOFT_ECC_CODE_NUM  3


#define NAND_MAX_CHIPS		8
#define NAND_MAX_OOB_SIZE	64
#define NAND_MAX_PAGESIZE	2048


#define NAND_NCE		0x01
#define NAND_CLE		0x02
#define NAND_ALE		0x04

#define NAND_CTRL_CLE		(NAND_NCE | NAND_CLE)
#define NAND_CTRL_ALE		(NAND_NCE | NAND_ALE)
#define NAND_CTRL_CHANGE	0x80


#define NAND_STATUS_FAIL        0x01
#define NAND_STATUS_FAIL_N1     0x02
#define NAND_STATUS_TRUE_READY  0x20
#define NAND_STATUS_READY       0x40
#define NAND_STATUS_WP          0x80


#define NAND_ECC_READ		0
#define NAND_ECC_WRITE		1
#define NAND_ECC_READSYN	2


#define NAND_NO_AUTOINCR	0x00000001
#define NAND_BUSWIDTH_16	0x00000002
#define NAND_NO_PADDING		0x00000004
#define NAND_CACHEPRG		0x00000008
#define NAND_COPYBACK		0x00000010
#define NAND_IS_AND		    0x00000020
#define NAND_4PAGE_ARRAY	0x00000040
#define BBT_AUTO_REFRESH	0x00000080
#define NAND_NO_READRDY		0x00000100
#define NAND_NO_SUBPAGE_WRITE	0x00000200

#define NAND_SAMSUNG_LP_OPTIONS \
	(NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK)

#define NAND_CANAUTOINCR(pNandFlash) (!(pNandFlash->dwFlags & NAND_NO_AUTOINCR))
#define NAND_MUST_PAD(pNandFlash) (!(pNandFlash->dwFlags & NAND_NO_PADDING))
#define NAND_HAS_CACHEPROG(pNandFlash) ((pNandFlash->dwFlags & NAND_CACHEPRG))
#define NAND_HAS_COPYBACK(pNandFlash) ((pNandFlash->dwFlags & NAND_COPYBACK))

#define NAND_CHIP_OPTIONS_MSK	(0x0000ffff & ~NAND_NO_AUTOINCR)
#define NAND_USE_FLASH_BBT	0x00010000
#define NAND_SKIP_BBTSCAN	0x00020000
#define NAND_OWN_BUFFERS	0x00040000


typedef enum {
	FL_READY,
	FL_READING,
	FL_WRITING,
	FL_ERASING,
	FL_SYNCING,
	FL_CACHEDPRG,
	FL_PM_SUSPENDED,
} NAND_STATE;


struct NandBuffer {
	BYTE ecccalc[NAND_MAX_OOB_SIZE];
	BYTE ecccode[NAND_MAX_OOB_SIZE];
	BYTE pDataBuf[NAND_MAX_PAGESIZE + NAND_MAX_OOB_SIZE];
};


struct NandFlash;
struct NandCtrl;

struct NandBbtpDesc
{
	int	  dwFlags;
	int	  pages[NAND_MAX_CHIPS];
	int	  offs;
	int	  veroffs;
	int	  len;
	int	  maxblocks;
	int	  reserved_block_code;
	BYTE  version[NAND_MAX_CHIPS];
	BYTE *pattern;
};


struct NandFlash
{
	struct Flash parent;

	struct NandCtrl *pMaster;

	UINT32  bDeviceID;
	UINT32  bVendorID;

	UINT32	dwFlags;

	int		phys_erase_shift;
	int		bbt_erase_shift;

	int		dwPageNumMask;

	int		nPageInBuff;

	int		nBadBlkOobPos;

	struct OobOpt ops;

	BYTE	*bbt;

	BYTE	*pOobBuf;

	struct NandBuffer   *buffers;

	struct NandBbtpDesc	*bbt_td;
	struct NandBbtpDesc	*bbt_md;
	struct NandBbtpDesc	*badblock_pattern;


	UINT32 nNandID;

	char    szName[MTD_DEV_NAME_LEN];

	struct ListNode nodeFlash;
};


struct NandCtrl
{
	void  	*pReadDataAddr;
	void  	*pWriteDataAddr;

	int		nChips;
	UINT32  nMaxSlaves;

	int		nChipDelay;
	NAND_STATE	eNandState;

// private :
	BYTE   (*ReadByte)(struct NandCtrl *);
	UINT16 (*ReadWord)(struct NandCtrl *);
	void   (*RawWrite)(struct NandCtrl *, const BYTE *, int);
	void   (*RawRead)(struct NandCtrl *, BYTE *, int);
	int	   (*VerifyBuffer)(struct NandCtrl *, const BYTE *, int);
	void   (*SelectChip)(struct NandFlash *, BOOL);
	int	   (*BlockBad)(struct NandFlash *, ULONG, int);
	int	   (*BlockMarkBad)(struct NandFlash *, ULONG);
	void   (*CmdCtrl)(struct NandFlash *, int, unsigned int);
	int	   (*FlashIsReady)(struct NandFlash *);
	void   (*Command)(struct NandFlash *, unsigned, int, int);
	int	   (*WaitFunc)(struct NandFlash *);
	void   (*EraseBlock)(struct NandFlash *, int);
	int	   (*ScanBadBlock)(struct NandFlash *);

// public:
	int   (*ReadPage)(struct NandFlash *, BYTE *);
	void  (*WritePage)(struct NandFlash *, const BYTE *);
	int	  (*ReadPageRaw)(struct NandFlash *, BYTE *);
	void  (*WritePageRaw)(struct NandFlash *, const BYTE *);
	int	  (*ReadOob)(struct NandFlash *, int, int);
	int	  (*WriteOob)(struct NandFlash *, int);

	ECC_MODE	eEccMode;

	struct NandOobLayout *pHardOobLayout;
	struct NandOobLayout *pSoftOobLayout;
	struct NandOobLayout *pCurOobLayout;

	UINT32  nEccDataLen;
	UINT32  nEccCodeNum;

	void	(*EccEnable)(struct NandFlash *, int);
	int		(*EccGenerate)(struct NandFlash *, const BYTE *, BYTE *);
	int		(*EccCorrect)(struct NandFlash *, BYTE *,  BYTE *,  BYTE *);

	char    szNcName[MTD_DEV_NAME_LEN];

	struct ListNode listFlash;
};


int GkNandCtrlRegister(struct NandCtrl *);

struct NandCtrl *GkNandCtrlNew(void);


#define NAND_MFR_TOSHIBA	0x98
#define NAND_MFR_SAMSUNG	0xec
#define NAND_MFR_FUJITSU	0x04
#define NAND_MFR_NATIONAL	0x8f
#define NAND_MFR_RENESAS	0x07
#define NAND_MFR_STMICRO	0x20
#define NAND_MFR_HYNIX		0xad
#define NAND_MFR_MICRON		0x2c
#define NAND_MFR_AMD		0x01


struct NandFlashpDesc {
	char *name;
	int id;
	unsigned long nPageSize;
	unsigned long nChipSize;
	unsigned long nEraseSize;
	unsigned long dwFlags;
};


struct NandVendor {
	int   id;
	char *pchVenName;
};


#define NAND_BBT_NRBITS_MSK	0x0000000F
#define NAND_BBT_1BIT		0x00000001
#define NAND_BBT_2BIT		0x00000002
#define NAND_BBT_4BIT		0x00000004
#define NAND_BBT_8BIT		0x00000008

#define	NAND_BBT_LASTBLOCK	0x00000010
#define NAND_BBT_ABSPAGE	0x00000020
#define NAND_BBT_SEARCH		0x00000040
#define NAND_BBT_PERCHIP	0x00000080
#define NAND_BBT_VERSION	0x00000100
#define NAND_BBT_CREATE		0x00000200
#define NAND_BBT_SCANALLPAGES	0x00000400
#define NAND_BBT_SCANEMPTY	0x00000800
#define NAND_BBT_WRITE		0x00001000
#define NAND_BBT_SAVECONTENT	0x00002000
#define NAND_BBT_SCAN2NDPAGE	0x00004000

#define NAND_BBT_SCAN_MAXBLOCKS	4

int NandUpdateBbt(struct NandFlash *, ULONG offs);
int NandScanBbt(struct NandFlash *);
int NandIsBadBbt(struct NandFlash *, ULONG offs);


#define NAND_BBP_LARGE		0
#define NAND_BBP_SMALL		5


#define TO_NANDFLASH(pFlash)            MemToObj(pFlash, struct NandFlash, parent)
#define NANDFLASH_GET_BASE(pNandFlash)  (&pNandFlash->parent)

